import path from "path";
import fs from "fs";
import { jsPDF, TextOptionsLight } from "jspdf";
import "./heiti-normal.js";
import XLSX from "xlsx";
import { parse } from "smol-toml";
import { drawBagLabel } from "./bag.js";
import { drawDocLabel } from "./doc.js";

interface Point {
  x: number;
  y: number;
}

interface Rect {
  w: number;
  h: number;
}

type Gap = Point;

interface Profile {
  name: string;
  paper_size: Rect;
  label_size: Rect;
  gap: Gap;
  zero_point: Point;
}

const INPUT_PROFILE = process.argv[2];
const INPUT_FILE = process.argv[3];

async function main() {
  usage();

  const config: any = readTomlConfig("config.toml");

  const profile = config[INPUT_PROFILE] as Profile;
  showProfile(profile);

  const contents = readXlsx(INPUT_FILE);
  console.log("f", contents);

  drawLabels(profile, contents, "res.pdf", true);
  console.log("Done");
}

main();

function usage() {
  console.log(`
npm run dev <profile> <xlsx_file>
    `);
}
function readTomlConfig(filePath: string): object {
  const content = fs.readFileSync(filePath, "utf8");
  return parse(content);
}

function readXlsx(filePath: string): string[][] {
  const wb = XLSX.readFile(filePath);
  const ws = wb.Sheets[wb.SheetNames[0]];
  return XLSX.utils.sheet_to_json(ws, { header: 1 });
}

function drawLabels(
  profile: Profile,
  contents: string[][],
  filePath: string,
  withBorder: boolean = false,
) {
  const { paper_size, label_size, gap, zero_point } = profile;
  const { row, col } = calcMaxRowCol(paper_size, label_size, gap, zero_point);

  const orientation = paper_size.w > paper_size.h ? "landscape" : "portrait";
  const pdf = new jsPDF({
    orientation: orientation, // 方向要根据纸张尺寸设置，这里是横向
    unit: "mm",
    format: [paper_size.w, paper_size.h],
  });

  const myFont = fs.readFileSync("./heiti.ttf"); // load the *.ttf font file as binary string

  // add the font to jsPDF
  pdf.addFileToVFS("MyFont.ttf", myFont.toString("binary"));
  pdf.addFont("MyFont.ttf", "MyFont", "normal");
  pdf.setFont("MyFont");

  // pdf.setFont('heiti')

  const perPageCount = row * col;

  let pageIndex = 0;

  const head = contents.shift() ?? [];
  for (let i = 0; i < contents.length; i++) {
    const innerPageIndex = i % perPageCount;
    const pageNum = Math.floor(i / perPageCount);
    if (pageNum > pageIndex) {
      pdf.addPage();
      pageIndex = pageNum;
    }

    const labelPoint = calcPos(
      zero_point,
      label_size,
      gap,
      col,
      innerPageIndex,
    );

    console.log("dfd", labelPoint);

    // const labelContents = contents[i].map(
    //   (v: any, j: number) => `${head[j]}： ${v}`,
    // );
    // drawOneLabel(pdf, label_size, labelPoint, labelContents, 2, withBorder);

    // drawBagLabel(pdf, label_size, labelPoint, contents[i]);
    //
    drawDocLabel(pdf, label_size, labelPoint, contents[i]);
  }

  console.log(`共生成 ${pageIndex + 1} 页，${contents.length} 张标签`);

  // 保存PDF文档
  pdf.save(tryFilePath(filePath));
}

/**
 * 绘制标签内容，不同的配置这个函数要对应修改
 * @param pdf pdf对象
 * @param label 标签尺寸
 * @param point 标签左上角位置
 * @param content 内容
 * @param radius 圆角半径
 * @param withBorder 是否要边框
 * @returns
 */
function drawOneLabel(
  pdf: jsPDF,
  label: Rect,
  point: Point,
  content: string[],
  radius: number,
  withBorder: boolean = true,
) {
  const { w, h } = label;
  const { x, y } = point;
  if (withBorder) {
    pdf.setLineWidth(1);
    pdf.setDrawColor("#0000FF");
    pdf.roundedRect(x, y, w, h, radius, radius).fill();
  }

  drawCenterText(pdf, label, point, "存档文件", 32, -20);
  drawCenterText(pdf, label, point, content[1], 12, -10);

  drawLeftText(pdf, label, point, content[0], 10, 3, 45);

  drawLeftText(pdf, label, point, content[2], 10, 45, 45);

  return pdf;
}

// /**
//  * 绘制标签内容，不同的配置这个函数要对应修改
//  * @param pdf pdf对象
//  * @param label 标签尺寸
//  * @param point 标签左上角位置
//  * @param content 内容
//  * @param radius 圆角半径
//  * @param withBorder 是否要边框
//  * @returns
//  */
// function drawBagLabel(
//   pdf: jsPDF,
//   label: Rect,
//   point: Point,
//   content: string[],
//   radius: number,
//   withBorder: boolean = true,
// ) {
//   const { w, h } = label;
//   const { x, y } = point;

//   if (withBorder) {
//     pdf.setLineWidth(1);
//     pdf.setDrawColor("#ffc0cb");
//     pdf.roundedRect(x, y, w, h, radius, radius).fill();
//   }

//   console.log("fd", label, point, content[1]);
//   drawCenterText(pdf, label, point, content[1], 32, -15);
//   drawCenterText(pdf, label, point, content[2], 22, 5);
//   drawCenterText(pdf, label, point, content[3], 22, 15);
//   // drawLeftText(pdf, label, point, content[2], 22, 45, 45);

//   return pdf;
// }

function calcPos(
  zeroPoint: Point,
  label: Rect,
  gap: Gap,
  col: number,
  index: number,
) {
  const { w, h } = label;
  const { x: startX, y: startY } = zeroPoint;
  const posX = startX + (index % col) * (w + gap.x);
  const posY = startY + Math.floor(index / col) * (h + gap.y);
  return { x: posX, y: posY };
}

/**
 * 计算纸张上最大行数列数
 * @param paper 纸张尺寸
 * @param label 标签尺寸
 * @param gap 间隔尺寸
 * @returns 行数列数
 */
function calcMaxRowCol(
  paper: Rect,
  label: Rect,
  gap: Gap,
  zeroPoint: Point,
): { row: number; col: number } {
  const maxCol = Math.floor(
    (paper.w - zeroPoint.x + gap.x) / (label.w + gap.x),
  );
  const maxRow = Math.floor(
    (paper.h - zeroPoint.y + gap.y) / (label.h + gap.y),
  );
  return { row: maxRow, col: maxCol };
}

/**
 * 展示配置
 * @param paper 纸张尺寸
 * @param label 标签尺寸
 * @param gap 间隔尺寸
 * @param zeroPoint 原点位置
 */
function showProfile(profile: Profile) {
  const { paper_size, label_size, gap, zero_point } = profile;
  const { row, col } = calcMaxRowCol(paper_size, label_size, gap, zero_point);
  console.log(`参数（mm）：
纸张宽高：${paper_size.w}, ${paper_size.h}
标签宽高：${label_size.w}, ${label_size.h}
标签间隔：${gap.x}, ${gap.y}
标签原点：${zero_point.x}, ${zero_point.y}
一张纸上标签行列：${row} 行 ${col} 列
一张纸上标签数量：${row * col} 张
`);
}

/**
 * 绘制居中文本
 *
 * @param pdf 文档
 * @param label 标签宽高
 * @param labelPoint 标签坐标
 * @param text 文本
 * @param fontSize 字号
 * @param offsetY Y偏移量
 */
function drawCenterText(
  pdf: jsPDF,
  label: Rect,
  labelPoint: Point,
  text: string,
  fontSize: number,
  offsetY = 0,
) {
  pdf.setFontSize(fontSize);
  const dimension = pdf.getTextDimensions(text);
  const { x, y } = calcCenterTextLeftPoint(
    labelPoint,
    label,
    dimension,
    offsetY,
  );
  pdf.text(text, x, y);
}

function drawLeftText(
  pdf: jsPDF,
  label: Rect,
  labelPoint: Point,
  text: string,
  fontSize: number,
  offsetX = 0,
  offsetY = 0,
) {
  pdf.setFontSize(fontSize);
  const dimension = pdf.getTextDimensions(text);
  if (offsetX + dimension.w > label.w) {
    console.error(`${text} 宽度超出尺寸范围 ${label.w}`);
  }
  if (offsetY + dimension.h > label.h) {
    console.log("gg", offsetY, dimension.h, label.h);

    console.error(`${text} 高度超出尺寸范围 ${label.h}`);
  }
  const { x, y } = calcLeftTextPoint(labelPoint, offsetX, offsetY);
  const opt: TextOptionsLight = {
    align: "left",
    maxWidth: label.w,
  };
  pdf.text(text, x, y, opt);
}

function calcLeftTextPoint(point: Point, offsetX = 0, offsetY = 0) {
  const { x, y } = point;
  return {
    x: x + offsetX,
    y: y + offsetY,
  };
}

function calcCenterTextLeftPoint(
  point: Point,
  label: Rect,
  dimension: Rect,
  offsetY = 0,
) {
  const { x, y } = point;
  const { w: labelW, h: labelH } = label;
  const { w: fontW, h: fontH } = dimension;
  return {
    x: x + (labelW / 2 - fontW / 2),
    y: y + (labelH / 2 + fontH / 2 - 1) + offsetY,
  };
}

function tryFilePath(val: string): string {
  let newPath = val;
  const dir = path.dirname(val);
  const ext = path.extname(val);
  const base = path.basename(val, ext);
  let i = 1;
  while (fs.existsSync(newPath)) {
    newPath = path.join(dir, `${base}(${i})${ext}`);
    i++;
  }
  return newPath;
}
